{ "cells": [ { "attachments": {}, "cell_type": "markdown", "id": "cdfe31cd-6fe1-41a6-84c8-34c51609fbb4", "metadata": { "raw_mimetype": "text/restructuredtext" }, "source": [ "# Linear Algebra\n", "\n", "## Dense / full eigen decomposition\n", "\n", "Currently full decompositions use numpy. They are as follows:\n", "\n", "> - {func}`~quimb.linalg.base_linalg.eig`\n", "> - {func}`~quimb.linalg.base_linalg.eigh`\n", "> - {func}`~quimb.linalg.base_linalg.eigvals`\n", "> - {func}`~quimb.linalg.base_linalg.eigvalsh`\n", "> - {func}`~quimb.linalg.base_linalg.eigvecs`\n", "> - {func}`~quimb.linalg.base_linalg.eigvecsh`\n", "> - {func}`~quimb.linalg.base_linalg.eigensystem`\n", "> - {func}`~quimb.linalg.base_linalg.svd`\n", "\n", "### Automatic Exploitation of Symmetries via Blocking\n", "\n", "Sometimes symmetries present themselves in an operator as, after\n", "a certain permutation, diagonal blocks. This fact can be exploited\n", "to speed up full eigen-decompositions as each block can be\n", "decomposed individually. For example, imagine we want to supply\n", "the eigen-decomposition of the Heisenberg Hamiltonian to an\n", "{class}`~quimb.evo.Evolution` object to perform long-time, exact,\n", "dynamics:" ] }, { "cell_type": "code", "execution_count": 1, "id": "407febc5-d58e-44d1-854f-bf5ba3a171fc", "metadata": {}, "outputs": [], "source": [ "import quimb as qu\n", "\n", "H = qu.ham_heis(12)" ] }, { "cell_type": "code", "execution_count": 2, "id": "440e9bed-fd71-4969-a2aa-84e5070d6f61", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "9.17 s ± 850 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" ] } ], "source": [ "%%timeit\n", "el, ev = qu.eigh(H)" ] }, { "cell_type": "markdown", "id": "74fd1d50-ce0f-422e-a633-7e25e10a0f3f", "metadata": {}, "source": [ "This is already quite slow, and will not be sustainable for larger lengths.\n", "The Heisenberg Hamiltonian however has an abelian $Z_2$ subgroup symmetry,\n", "conserved Z-spin, that manifests itself in the computational basis.\n", "Thus if instead we specify ``autoblock=True``:" ] }, { "cell_type": "code", "execution_count": 3, "id": "49a3df73-6afa-4083-a86e-c5828c7eddd6", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "466 ms ± 63.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" ] } ], "source": [ "%%timeit\n", "el, ev = qu.eigh(H, autoblock=True)" ] }, { "attachments": {}, "cell_type": "markdown", "id": "63a9a721-9ed8-4fb3-8d6a-58eac85196dd", "metadata": { "raw_mimetype": "text/restructuredtext" }, "source": [ "We can see a drastic speedup (helped by the fact that the whole algorithm uses `numba`).\n", "To work more fundamentally with the indentified blocks see the\n", "{func}`~quimb.linalg.autoblock.compute_blocks` function.\n", "\n", "## Partial eigen decomposition\n", "\n", "Partial decompositions are mostly just specified by supplying the `k` kwarg to the above functions. These also take a `backend` argument which can be one of:\n", "\n", "- `'scipy'`: is generally reliable\n", "- `'numpy'`: can be faster for small or dense problems\n", "- `'lobpcg'`: useful for fast, low accruacy generalized eigenproblems (like periodic DMRG)\n", "- `'slepc'`: Usually the fastest for large problems, with many options. Will either spawn MPI\n", " workers or should be used in `syncro` mode.\n", "- `'slepc-nompi'`: like `'slepc'`, but performs computation in the single, main process.\n", "- `'AUTO'` - choose a good backend, the default.\n", "\n", "The possible partical decompositions are:\n", "\n", "> - {func}`~quimb.linalg.base_linalg.eig` with `(k > 0)`\n", "> - {func}`~quimb.linalg.base_linalg.eigh` with `(k > 0)`\n", "> - {func}`~quimb.linalg.base_linalg.eigvals` with `(k > 0)`\n", "> - {func}`~quimb.linalg.base_linalg.eigvalsh` with `(k > 0)`\n", "> - {func}`~quimb.linalg.base_linalg.eigenvectors` with `(k > 0)`\n", "> - {func}`~quimb.linalg.base_linalg.eigvecs` with `(k > 0)`\n", "> - {func}`~quimb.linalg.base_linalg.eigvecsh` with `(k > 0)`\n", "> - {func}`~quimb.linalg.base_linalg.groundstate`\n", "> - {func}`~quimb.linalg.base_linalg.groundenergy`\n", "> - {func}`~quimb.linalg.base_linalg.eigensystem_partial`\n", "> - {func}`~quimb.linalg.base_linalg.svds`\n", "\n", "So for example the {func}`~quimb.linalg.base_linalg.groundstate` function\n", "for a Hamiltonian `H` is an alias to:" ] }, { "cell_type": "code", "execution_count": 5, "id": "2b325bd8-e06b-43bf-bcc1-627cab652a1c", "metadata": {}, "outputs": [], "source": [ "psi = qu.eigvecsh(H, k=1, which=\"SA\")" ] }, { "cell_type": "markdown", "id": "1382b7ce-4484-4c3a-b8db-956fff93b749", "metadata": { "raw_mimetype": "text/restructuredtext" }, "source": [ "\\[find eigenvectors, Hermitian operator (`h` post-fix), get `k=1` eigenstate,\n", "and target the '(s)mallest (a)lgebraic' eigenvalue\\].\n", "\n", "## Interior eigen-solving\n", "\n", "SLEPc is highly recommended for performing these using 'shift-invert'.\n", "See the following functions:\n", "\n", "> - `eigh(..., k=k, sigma=x)` with `k > 0` etc., or\n", "> - {func}`~quimb.linalg.base_linalg.eigh_window`\n", "> - {func}`~quimb.linalg.base_linalg.eigvalsh_window`\n", "> - {func}`~quimb.linalg.base_linalg.eigvecsh_window`\n", "\n", "With the last three allowing the specification of a window *relative* to the total spectrum of the operator.\n", "\n", "## Fast Randomized Linear Algebra\n", "\n", "`quimb` has an implementation of a fast randomized SVD - {func}`~quimb.linalg.rand_linalg.rsvd` -\n", "that can be significantly quicker than {func}`~quimb.linalg.base_linalg.svd` or {func}`~quimb.linalg.base_linalg.svds`,\n", "especially for large `k`. This might be useful for e.g. tensor network linear operator decompositions.\n", "It can perform the SVD rank-adaptively, which allows the efficient estimation of an operator's rank,\n", "see {func}`~quimb.linalg.rand_linalg.estimate_rank`." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3" }, "vscode": { "interpreter": { "hash": "39c10650315d977fb13868ea1402e99f3e10e9885c2c202e692ae90b8995050d" } } }, "nbformat": 4, "nbformat_minor": 2 }